package com.yuntsg.ruiijn.databse_search.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.util.StrUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.twelvemonkeys.image.ImageUtil;
import com.yuntsg.ruiijn.databse_search.BaseService;
import com.yuntsg.ruiijn.databse_search.entity.*;
import com.yuntsg.ruiijn.databse_search.mapper.FolderTypeMapper;
import common.util.*;
import common.vo.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.Rect;
import org.opencv.imgcodecs.Imgcodecs;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.awt.*;
import java.io.ByteArrayInputStream;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
@DS("master")
@SuppressWarnings("all")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class FolderTypeService extends BaseService<FolderTypeMapper, FolderType> {


    private final FileDetailService fileDetailService;
    private final ImageComparison imageComparison;
    private final SearchRecordService searchRecordService;
    private final SearchSelfService searchSelfService;
    private final BussService bussService;
    private final MinioUtil minioUtil;
    private final ExtractUtil extractUtil;
    private final FileRecordsService fileRecordsService;
    private final FeatureService featureService;
    private final NacosUtil nacosUtil;
    @Value("${central.search.singleNum}")
    private Integer singleNum;
    @Value("${central.search.allNum}")
    private Integer allNum;

    public List<ContentsComparisonRes> anycGenRecodSingle(Integer id, SearchRecord record) {
        TimeInterval timer = DateUtil.timer();
        Integer rid = record.getRId();
        Integer uid = record.getUId();
        Integer topk = record.getTopk();
        Integer level = record.getLevel();
        Integer source = record.getSource();
        FileDetails fileDetails = fileDetailService.getById(id);
        if (null == fileDetails) {
            return null;
        }
        FileRecord fileRecord = fileRecordsService.getById(rid);
        List<Float> floats = featureService.imageFeature(fileDetails.getPath());
        FetchVectorVoStep fetchVectorVoStep;
        if (source == 2) {
            fetchVectorVoStep = searchSelfService.pubSearchImage(topk, floats.stream().map(Float::doubleValue).collect(Collectors.toList()), record.getRids().stream().map(String::valueOf).collect(Collectors.toList()), Optional.ofNullable(fileRecord.getPmut()).orElse(""));
        } else {
            fetchVectorVoStep = searchSelfService.pubSearchImage(allNum, floats.stream().map(Float::doubleValue).collect(Collectors.toList()), source, Optional.ofNullable(fileRecord.getPmut()).orElse(""));
        }
        log.info("{},检索耗时：{}", id, timer.interval());
        List<FolderType> list = this.list(Wrappers.<FolderType>lambdaQuery().eq(FolderType::getType, 1).eq(FolderType::getMainId, fileDetails.getId()).eq(FolderType::getRId, fileDetails.getRid()).eq(FolderType::getUId, uid));
        FolderType folderType = new FolderType();
        list = list.stream().filter(l -> null != l.getListId()).collect(Collectors.toList());
        if (list.size() > 0) {
            if (list.size() > 1) {
                Set<Integer> collect = list.stream().flatMap(f -> f.getListId().stream()).collect(Collectors.toSet());
                folderType = list.get(0);
                this.saveOrUpdate(folderType.setListId(new ArrayList<>(collect)));
                for (int i = 1; i < list.size(); i++) {
                    this.removeById(list.get(i).getId());
                }
            } else {
                folderType = list.get(0);
            }
        } else {
            FolderType folderTypeNew = new FolderType();
            folderTypeNew.setFolderName(fileDetails.getId().toString());
            folderTypeNew.setUId(uid);
            folderTypeNew.setRId(fileDetails.getRid());
            folderTypeNew.setType(1);
            folderTypeNew.setMainId(fileDetails.getId());
            this.save(folderTypeNew);
            folderType = folderTypeNew;
        }
        List<Integer> listId = Optional.ofNullable(folderType.getListId()).orElse(new ArrayList<>());
        List<FileDetails> oList = new ArrayList<>();
        oList.add(fileDetails);
        if (fetchVectorVoStep != null) {
            List<ComparisonRes> lineTemp = new ArrayList<>();
            List<ComparisonRes> firstTemp = new ArrayList<>();
            List<PubVectorImageRes> datas = fetchVectorVoStep.getData();
            List<List<PubVectorImageRes>> lists = ImageComparison.groupListByCount(datas, topk);

            for (int i = 0; i < lists.size(); i++) {
//                log.info("id：{},第{}组", id, i + 1);
                List<FileDetails> tList = new ArrayList<>();
                TimeInterval timerinner = DateUtil.timer();
                for (PubVectorImageRes data : lists.get(i)) {
                    Integer table_no = data.getTable_no();
                    Integer serial_id = data.getSerial_id();
                    if (null == table_no || null == serial_id) {
                        continue;
                    }
                    Integer top_x = data.getTop_x();
                    Integer top_y = data.getTop_y();
                    Integer bottom_x = data.getBottom_x();
                    Integer bottom_y = data.getBottom_y();
                    String pmid_ut = data.getPm();
                    String img_name = data.getImg_name();
                    List<Float> vector = data.getVector();

                    FileDetails one = fileDetailService.getOne(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getTpye, -1).eq(FileDetails::getTableNo, table_no).eq(FileDetails::getSerialId, serial_id).last("limit 1"));

                    String tableMark = "ncbi_pdf_to_jpg_" + table_no;
                    NcbiPdfToJpg imageData;
                    try {
                        imageData = bussService.getImgData(serial_id, tableMark);
                    } catch (Exception e) {
                        continue;
                    }
                    Integer fid = null;

                    if (null == one) {
                        String fileName = imageData.getFileName();
                        String path = minioUtil.upload(new ByteArrayInputStream(imageData.getFigureZip()), uid, DateUtil.today(), fileName, Scenario.view);
                        FileDetails fileDetailsInner = new FileDetails().setFId(rid).setRid(rid).setTpye(-1).setTableNo(table_no).setSerialId(serial_id).setPath(path).setPmid(AesEncryptUtils.encrypt(imageData.getPmidUt()));
                        fileDetailService.save(fileDetailsInner);
                        fid = fileDetailsInner.getId();
                    } else {
                        fid = one.getId();
                    }

                    FileDetails fileDetailInner = fileDetailService.getOne(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getFId, fid).eq(FileDetails::getTpye, -2).eq(FileDetails::getRid, rid).eq(FileDetails::getTopX, top_x).eq(FileDetails::getTopY, top_y).eq(FileDetails::getBottomX, bottom_x).eq(FileDetails::getBottomY, bottom_y).last("limit 1"));

                    if (null == fileDetailInner) {
                        FileDetails fileDetailsSave = new FileDetails();
                        fileDetailsSave.setFId(fid);
                        fileDetailsSave.setRid(rid);
                        fileDetailsSave.setTpye(-2);
                        fileDetailsSave.setSplitStatus(1);
                        fileDetailsSave.setPmid(AesEncryptUtils.encrypt(imageData.getPmidUt()));
                        fileDetailsSave.setCollectionStatus(folderType.getId());
                        fileDetailsSave.setDeleteFlag(-1);
                        Image image = extractUtil.byteArrayToImage(imageData.getFigureZip());
                        if (null == image) {
                            continue;
                        }
                        String path = null;

                        try {
                            Mat src = Imgcodecs.imdecode(new MatOfByte(imageData.getFigureZip()), Imgcodecs.IMREAD_COLOR);
                            Mat croppedImage = new Mat(src, new Rect(top_x, top_y, bottom_x - top_x, bottom_y - top_y));
                            path = minioUtil.upload(minioUtil.coverInput(croppedImage), uid, DateUtil.today(), img_name, Scenario.view);
                        } catch (Exception e) {
                            log.info("错误图片宽：{}，高：{}", ImageUtil.getWidth(image), ImageUtil.getHeight(image));
                            continue;
                        }

                        fileDetailsSave.setPath(path);
                        fileDetailsSave.setTopX(top_x);
                        fileDetailsSave.setTopY(top_y);
                        fileDetailsSave.setBottomX(bottom_x);
                        fileDetailsSave.setBottomY(bottom_y);
                        fileDetailsSave.setVector(vector);
                        fileDetailService.save(fileDetailsSave);
                        tList.add(fileDetailsSave);

                    } else {
                        tList.add(fileDetailInner.setVector(vector));
                    }
                }

                if (tList.size() == 0) {
                    continue;
                }
//                log.info("id：{},第{}组 数据下载耗时：", id, i + 1, timerinner.intervalRestart());

                tList.stream().filter(f -> !StrUtil.isNullOrUndefined(f.getPath())).forEach(f -> {
                    f.setArray(nacosUtil.numIdentify(f.getPath()));
                    if (null == f.getVector() || f.getVector().size() == 0) {
                        f.setVector(featureService.imageFeature(f.getPath()));
                    }
                    if (null == f.getPath()) {
                        f.setIsWhite(false);
                    } else {
                        f.setIsWhite(imageComparison.checkWhiteBlock(f.getPath()));
                    }
                });
                oList.stream().filter(f -> !StrUtil.isNullOrUndefined(f.getPath())).forEach(f -> {
                    f.setArray(nacosUtil.numIdentify(f.getPath()));
                    if (null == f.getVector() || f.getVector().size() == 0) {
                        f.setVector(featureService.imageFeature(f.getPath()));
                    }
                    if (null == f.getPath()) {
                        f.setIsWhite(false);
                    } else {
                        f.setIsWhite(imageComparison.checkWhiteBlock(f.getPath()));
                    }
                });

//                log.info("id：{},第{}组 数据组装耗时：",id,i+1,timerinner.intervalRestart());
                List<ContentsComparisonRes> contentsComparisonRes = imageComparison.comparisonSortWithLine(oList, tList, uid, 0, level, null, "inform.normal");
//                log.info("id：{},第{}组 图片对比耗时：",id,i+1,timerinner.intervalRestart());
                if (contentsComparisonRes.get(0).getHasPiclist().size() > 0) {
                    lineTemp.addAll(contentsComparisonRes.get(0).getHasPiclist());
                }
                if (i == 0) {
                    firstTemp = contentsComparisonRes.get(0).getList();
                }
                if (lineTemp.size() >= topk * 0.8) {
                    break;
                }
            }

            if (lineTemp.size() > 0) {
                firstTemp.addAll(lineTemp);
            }
            if (firstTemp.size() > 0) {
                firstTemp = firstTemp.stream().distinct().limit(topk).collect(Collectors.toList());
                ContentsComparisonRes contentsComparisonResReal = new ContentsComparisonRes();
                contentsComparisonResReal.setMax(firstTemp.stream().mapToDouble(ComparisonRes::getV).max().getAsDouble());
                contentsComparisonResReal.setIsShow(firstTemp.stream().filter(ComparisonRes::isHasPic).findAny().isPresent() ? 1 : 0);
                contentsComparisonResReal.setFileDetails(fileDetails);
                contentsComparisonResReal.setList(firstTemp);
                listId.addAll(firstTemp.stream().map(v -> v.getFileDetails().getId()).collect(Collectors.toList()));
                this.saveOrUpdate(folderType.setListId(listId));
                return Arrays.asList(contentsComparisonResReal);
            }
            return null;
        }

        return null;
    }


    /**
     * 生成对比结果
     */
    //@Async
//    public void anycGenRecod(String[] ids, Integer uid, Integer rid, Integer reId, Integer topk) throws IOException {
//        System.out.println("进入对比结果 2");
//        for (FileDetails fileDetails : fileDetailService.listByIds(Arrays.asList(ids))) {
//            rid = fileDetails.getRid();
//            List<Float> floats = featureService.imageFeature(fileDetails.getPath());
//            FetchVectorVoStep fetchVectorVoStep = searchSelfService.pubSearchImage(topk, floats.stream().map(Float::doubleValue).collect(Collectors.toList()), 0, "0");
//            FolderType folderType = this.getOne(Wrappers.<FolderType>lambdaQuery().eq(FolderType::getType, 1).eq(FolderType::getMainId, fileDetails.getId()).eq(FolderType::getRId, fileDetails.getRid()).eq(FolderType::getUId, uid));
//            if (null == folderType) {
//                FolderType folderTypeNew = new FolderType();
//                folderTypeNew.setFolderName(fileDetails.getId().toString());
//                folderTypeNew.setUId(uid);
//                folderTypeNew.setRId(fileDetails.getRid());
//                folderTypeNew.setType(1);
//                folderTypeNew.setMainId(fileDetails.getId());
//                this.save(folderTypeNew);
//                folderType = folderTypeNew;
//            }
//            List<Integer> listId = Optional.ofNullable(folderType.getListId()).orElse(new ArrayList<>());
//
//            for (PubVectorImageRes data : fetchVectorVoStep.getData()) {
//
//                Integer table_no = data.getTable_no();
//                Integer serial_id = data.getSerial_id();
//                Integer top_x = data.getTop_x();
//                Integer top_y = data.getTop_y();
//                Integer bottom_x = data.getBottom_x();
//                Integer bottom_y = data.getBottom_y();
//                String pmid_ut = data.getPm();
//                String img_name = data.getImg_name();
//                List<Float> vector = data.getVector();
//
//                FileDetails one = fileDetailService.getOne(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getTpye, -1).eq(FileDetails::getTableNo, table_no).eq(FileDetails::getSerialId, serial_id).last("limit 1"));
//
//                String tableMark = "ncbi_pdf_to_jpg_" + table_no;
//                NcbiPdfToJpg imageData;
//                try {
//                    imageData = bussService.getImgData(serial_id, tableMark);
//                } catch (Exception e) {
//                    continue;
//                }
//                Integer fid = null;
//
//                if (null == one) {
//                    String fileName = imageData.getFileName();
//                    String path = minioUtil.upload(new ByteArrayInputStream(imageData.getFigureZip()), uid, DateUtil.today(), fileName, Scenario.view);
//                    FileDetails fileDetailsInner = new FileDetails().setFId(rid).setRid(rid).setTpye(-1).setTableNo(table_no).setSerialId(serial_id).setPath(path).setPmid(AesEncryptUtils.encrypt(imageData.getPmidUt()));
//                    fileDetailService.save(fileDetailsInner);
//                    fid = fileDetailsInner.getId();
//                } else {
//                    fid = one.getId();
//                }
//
//                FileDetails fileDetailInner = fileDetailService.getOne(Wrappers.<FileDetails>lambdaQuery().eq(FileDetails::getFId, fid).eq(FileDetails::getTpye, -2).eq(FileDetails::getRid, rid).eq(FileDetails::getTopX, top_x).eq(FileDetails::getTopY, top_y).eq(FileDetails::getBottomX, bottom_x).eq(FileDetails::getBottomY, bottom_y).last("limit 1"));
//
//                if (null == fileDetailInner) {
//                    FileDetails fileDetailsSave = new FileDetails();
//                    fileDetailsSave.setFId(fid);
//                    fileDetailsSave.setRid(rid);
//                    fileDetailsSave.setTpye(-2);
//                    fileDetailsSave.setSplitStatus(1);
//                    fileDetailsSave.setPmid(AesEncryptUtils.encrypt(imageData.getPmidUt()));
//                    fileDetailsSave.setCollectionStatus(folderType.getId());
//                    fileDetailsSave.setDeleteFlag(-1);
//                    Image image = extractUtil.byteArrayToImage(imageData.getFigureZip());
//                    if (null == image) {
//                        continue;
//                    }
//
//                    Mat src = Imgcodecs.imdecode(new MatOfByte(imageData.getFigureZip()), Imgcodecs.IMREAD_COLOR);
//                    Mat croppedImage = new Mat(src, new Rect(top_x, top_y, bottom_x - top_x, bottom_y - top_y));
//                    String path = minioUtil.upload(minioUtil.coverInput(croppedImage), userUtil.getUid(), DateUtil.today(), img_name, Scenario.view);
//
//                    fileDetailsSave.setPath(path);
//                    fileDetailsSave.setTopX(top_x);
//                    fileDetailsSave.setTopY(top_y);
//                    fileDetailsSave.setBottomX(bottom_x);
//                    fileDetailsSave.setBottomY(bottom_y);
//                    fileDetailService.save(fileDetailsSave);
//                    listId.add(fileDetailsSave.getId());
//                }
//            }
//            this.saveOrUpdate(folderType.setListId(listId));
//        }
//
//        Map<Integer, List<Integer>> map = SimpleQuery.map(Wrappers.<FolderType>lambdaQuery().in(FolderType::getMainId, ids).eq(FolderType::getUId, uid).eq(FolderType::getRId, rid), FolderType::getMainId, FolderType::getListId);
//
//        List<ContentsComparisonRes> finalList = new ArrayList<>();
//        SearchRecord record = searchRecordService.getById(reId);
//        try {
//            map.keySet().stream().forEach(id -> {
//                List<FileDetails> oList = new ArrayList<>();
//                List<FileDetails> tList = new ArrayList<>();
//
//                FileDetails fileDetails = fileDetailService.getById(id);
//                oList.add(fileDetails.setVector(featureService.imageFeature(fileDetails.getPath())).setIsWhite(imageComparison.checkWhiteBlock(fileDetails.getPath())).setArray(nacosUtil.numIdentify(fileDetails.getPath())));
//
//                List<Integer> integers = map.get(id);
//                List<FileDetails> list = fileDetailService.listByIds(integers);
//
//                list.stream().forEach(f -> {
//                    f.setArray(nacosUtil.numIdentify(f.getPath()));
//                    f.setVector(featureService.imageFeature(f.getPath()));
//                    f.setIsWhite(imageComparison.checkWhiteBlock(f.getPath()));
//                    tList.add(f);
//                });
//
//                List<ContentsComparisonRes> contentsComparisonRes = imageComparison.comparisonSortWithLine(oList, tList, uid, 0, null);
//                if (contentsComparisonRes.size() > 0) {
//                    finalList.add(contentsComparisonRes.get(0));
//                }
//            });
//            searchRecordService.saveOrUpdate(record.setJsonResult(finalList.stream().sorted(Comparator.comparingDouble(ContentsComparisonRes::getMax).reversed()).collect(Collectors.toList())).setFinishTime(System.currentTimeMillis()).setStatus(1).setReadStatus(-1));
//        } catch (Exception e) {
//            searchRecordService.saveOrUpdate(record.setFinishTime(System.currentTimeMillis()).setStatus(-1));
//        } finally {
//            MyWebSocketHandler.sendMessage(uid, "true");
//        }
//
//    }


}
